﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Wormhole.Engine.Decks
{
	/// <author>Rodney McKay</author>
	/// <date>07 April 2008</date>
	/// <summary>
	/// A base class for card decks.
	/// </summary>
	public class Deck : List<CardLibrary.BaseCardTypes.Card>
	{
		#region Delegates
		/// <summary>
		/// The delegate for the event handler that fires when a card is added.
		/// </summary>
		/// <param name="card">The card that was added.</param>
		public delegate void CardAddedDelegate(CardLibrary.BaseCardTypes.Card card);

		/// <summary>
		/// The delegate for the event handler that fires when a card is removed.
		/// </summary>
		/// <param name="card">The card that was removed.</param>
		public delegate void CardRemovedDelegate(CardLibrary.BaseCardTypes.Card card);

		/// <summary>
		/// The event delegate for when a card is taken into the players hand.
		/// </summary>
		/// <param name="card">The card taken.</param>
		public delegate void CardTakenDelegate(CardLibrary.BaseCardTypes.Card card);

		/// <summary>
		/// Remove the team cards from the deck.
		/// </summary>
		/// <param name="teamCards">A list of the team cards that were removed.</param>
		public delegate void TeamCardsRemovedDelegate(List<CardLibrary.BaseCardTypes.Card> teamCards);

		/// <summary>
		/// The delegate for the event that is fired when the mission cards are removed from the deck.
		/// </summary>
		/// <param name="missionCards">A list of mission cards that were removed.</param>
		public delegate void MissionCardsRemovedDelegate(List<CardLibrary.BaseCardTypes.Card> missionCards);
		#endregion

		#region Events
		/// <summary>
		/// The card added event.
		/// </summary>
		public event CardAddedDelegate CardAdded;

		/// <summary>
		/// The card removed event.
		/// </summary>
		public event CardRemovedDelegate CardRemoved;

		/// <summary>
		/// When  the player takes a card into his hand, this event is raised.
		/// </summary>
		public event CardTakenDelegate CardTaken;

		/// <summary>
		/// This event is raised when the team cards are removed.
		/// </summary>
		public event TeamCardsRemovedDelegate TeamCardsRemoved;

		/// <summary>
		/// This event is raised when the mission cards are removed.
		/// </summary>
		public event MissionCardsRemovedDelegate MissionCardsRemoved;

		/// <summary>
		/// This event is raised when the card is selected.
		/// </summary>
		public event Wormhole.Engine.CardLibrary.BaseCardTypes.Card.CardSelectedDelegate CardSelected;

		#endregion

		#region Properties
		#region Player
		private Engine.Player.Player _player;
		/// <summary>
		/// The game engine object holding the player score.
		/// </summary>
		public Engine.Player.Player Player
		{
			get
			{
				return this._player;
			}

			set
			{
				this._player = value;
				this.SetEngineEvents();
			}
		}
		#endregion

		#endregion

		#region Constructor
		/// <summary>
		/// Initialize a default instance of the class.
		/// </summary>
		public Deck()
		{

		}

		/// <summary>
		/// Create a new deck for a specific player.
		/// </summary>
		/// <param name="player">The player the deck belongs to.</param>
		public Deck(Player.Player player)
		{
			this.Player = player;
		}
		#endregion

		#region Add
		/// <summary>
		/// Add a card to the library and raise the add event.
		/// </summary>
		/// <param name="card">The card to add.</param>
		public virtual new void Add(CardLibrary.BaseCardTypes.Card card)
		{
			base.Add(card);
			this.OnCardAdd(card);
		}
		#endregion

		#region Remove
		/// <summary>
		/// Remove a card from the library
		/// </summary>
		/// <param name="card">The card to be removed.</param>
		/// <returns>Return true if the card was removed.</returns>
		public virtual new bool Remove(CardLibrary.BaseCardTypes.Card card)
		{
			bool result = base.Remove(card);
			this.OnCardRemoved(card);

			return result;
		}
		#endregion

		#region Take Card
		/// <summary>
		/// Remove a card from the library. 
		/// </summary>
		/// <returns>Returns the card that was taken, return null if there are no cards in the deck.</returns>
		public CardLibrary.BaseCardTypes.Card TakeCard()
		{
			CardLibrary.BaseCardTypes.Card card = null;

			if (this.Count > 0)
			{
				card = this[0];
				this.Remove(card);
				this.OnCardTaken(card);
			}

			return card;
		}
		#endregion

		#region Remove Cards
		/// <summary>
		/// Remove cards with a specific trait from the deck.
		/// </summary>
		/// <param name="cardTrait">The card trait to match for removed cards.</param>
		/// <returns>A collection of the cards that were removed.</returns>
		protected List<CardLibrary.BaseCardTypes.Card> RemoveCards(Wormhole.Engine.CardLibrary.CardProperties.Trait cardTrait)
		{
			List<CardLibrary.BaseCardTypes.Card> cardList = new List<Wormhole.Engine.CardLibrary.BaseCardTypes.Card>();

			// get the cards that have the team trait
			var cards = from deckCard in this
						where deckCard.Traits.Contains(cardTrait)
						select deckCard;

			// add the cards to the team list
			foreach (CardLibrary.BaseCardTypes.Card card in cards)
			{
				cardList.Add(card);
			}

			// remove the cards form the deck
			foreach (CardLibrary.BaseCardTypes.Card card in cardList)
			{
				this.Remove(card);
			}

			return cardList;
		}
		#endregion

		#region Remove Team Cards
		/// <summary>
		/// Remove the team cards from the deck.
		/// </summary>
		public void RemoveTeamCards()
		{
			this.OnTeamCardsRemoved(this.RemoveCards(Wormhole.Engine.CardLibrary.CardProperties.Trait.Team));
		}
		#endregion

		#region Remove Mission Cards
		/// <summary>
		/// Remove mission cards from the deck.
		/// </summary>
		public void RemoveMissionCards()
		{
			this.OnMissionCardsRemoved(this.RemoveCards(Wormhole.Engine.CardLibrary.CardProperties.Trait.Mission));
		}
		#endregion

		#region Set Player Events
		/// <summary>
		/// Wire up the events from other engine objects to listen for.
		/// </summary>
		protected virtual void SetEngineEvents()
		{
		}
		#endregion

		#region Shuffle
		/// <summary>
		/// Shuffle cards in the deck.
		/// </summary>
		public void Shuffle()
		{
			Random random = new Random(this.Player.RandomSeed);
			for (int i = 0; i < this.Count; i++)
			{
				int swapIndex = random.Next(0, this.Count - 1);
				CardLibrary.BaseCardTypes.Card swapCard = this[swapIndex];
				
				this[swapIndex] = this[i];
				this[i] = swapCard;
			}
		}
		#endregion

		#region On Card Add
		/// <summary>
		/// Raise the card added event.
		/// </summary>
		/// <param name="card">The card to raise the event for.</param>
		protected virtual void OnCardAdd(CardLibrary.BaseCardTypes.Card card)
		{
			// wire up the card events to listen for
			card.CardSelected += new Wormhole.Engine.CardLibrary.BaseCardTypes.Card.CardSelectedDelegate(card_CardSelected);

			// raise the card added event
			if (this.CardAdded != null)
				this.CardAdded(card);
		}
		#endregion

		#region On Card Removed
		/// <summary>
		/// Fire the card removed event.
		/// </summary>
		/// <param name="card">The card that was removed</param>
		protected virtual void OnCardRemoved(CardLibrary.BaseCardTypes.Card card)
		{
			// remove the event listeners
			card.CardSelected -= new Wormhole.Engine.CardLibrary.BaseCardTypes.Card.CardSelectedDelegate(card_CardSelected);

			if (this.CardRemoved != null)
				this.CardRemoved(card);
		}
		#endregion

		#region On Card Taken
		/// <summary>
		/// Fires the card taken event when the player takes a card into his hand.
		/// </summary>
		/// <param name="card">The card that was taken.</param>
		protected void OnCardTaken(CardLibrary.BaseCardTypes.Card card)
		{
			if (this.CardTaken != null)
				this.CardTaken(card);
		}
		#endregion

		#region On Team Cards Removed
		/// <summary>
		/// Raise the event that the team cards were removed.
		/// </summary>
		/// <param name="teamCards">The list of team cards that were removed.</param>
		protected void OnTeamCardsRemoved(List<CardLibrary.BaseCardTypes.Card> teamCards)
		{
			if (this.TeamCardsRemoved != null)
				this.TeamCardsRemoved(teamCards);
		}
		#endregion

		#region On Mission Cards Removed
		/// <summary>
		/// Raise the event that the mission cards were removed.
		/// </summary>
		/// <param name="missionCards">The list of mission cards that were removed.</param>
		protected void OnMissionCardsRemoved(List<CardLibrary.BaseCardTypes.Card> missionCards)
		{
			if (this.MissionCardsRemoved != null)
				this.MissionCardsRemoved(missionCards);
		}
		#endregion

		#region Event Handlers

		#region Card Selected
		/// <summary>
		/// Handle the card selected event.
		/// </summary>
		/// <param name="card"></param>
		private void card_CardSelected(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			if (this.CardSelected != null)
				this.CardSelected(card);
		}
		#endregion

		#endregion

		#region Find By ID
		/// <summary>
		/// Find a card by its ID.
		/// </summary>
		/// <param name="id">The ID of the card.</param>
		/// <returns>Returns the card or null if it was not found.</returns>
		public CardLibrary.BaseCardTypes.Card FindByID(int id)
		{
			foreach (CardLibrary.BaseCardTypes.Card card in this)
			{
				if (card.ID == id)
					return card;
			}

			return null;
		}
		#endregion
	}
}
